package com.lfs.admin.service;

import com.lfs.admin.config.MinioConfig;
import com.lfs.common.utils.file.FileUploadUtils;
import io.minio.*;
import io.minio.errors.*;
import io.minio.http.Method;
import io.minio.messages.Bucket;
import io.minio.messages.DeleteObject;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.io.InputStream;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.text.SimpleDateFormat;
import java.util.*;


/**
 * minio服务
 *
 * @author zhaorongxi
 * @date 2022/01/15
 */
@SuppressWarnings(value = {"unchecked", "rawtypes"})
@Component
@Slf4j
public class MinioService {


    @Autowired
    private MinioClient client;

    @Autowired
    private MinioConfig minioConfig;

    @Value("${allPrefix:['1','2','3']}")
    private Set<String> prefixSet;

    /**
     * 创建bucket
     */
    public void createBucket(String bucketName) throws Exception {
        if (!client.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build())) {
            client.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
        }
    }

    /**
     * 上传文件
     */
    public String uploadFile(MultipartFile file, String bucketName) throws Exception {
        //判断文件是否为空
        if (null == file || 0 == file.getSize()) {
            return null;
        }

        String prefix = FileUploadUtils.getExtension(file);
        if (prefixSet.contains(prefix)) {
            return "请求的文件后缀为非法后缀,请重新上传!";
        }

        //判断存储桶是否存在  不存在则创建
        createBucket(bucketName);
        //文件名
        String originalFilename = file.getOriginalFilename();
        //新的文件名 = 存储桶文件名_时间戳.后缀名
        assert originalFilename != null;
//        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
//        String fileName = bucketName + "_" + format.format(new Date()) + originalFilename;
        //开始上传
        client.putObject(
                PutObjectArgs.builder().bucket(bucketName).object(originalFilename).stream(
                        file.getInputStream(), file.getSize(), -1)
                        .contentType(file.getContentType())
                        .build());
        String url = minioConfig.getUrl() + "/" + bucketName + "/" + originalFilename;
//        String urlHost = minioConfig.getFilHost() + "/" + bucketName + "/" + fileName;
        log.info("上传文件成功url ：[{}]", url);
        return url;
    }

    /**
     * 上传文件路径
     *
     * @param bucketName bucket名称
     * @param objectKey  对象关键
     * @param filePath   文件路径
     * @return {@link ObjectWriteResponse}
     */
    public ObjectWriteResponse uploadByFilePath(String bucketName, String objectKey, String filePath) {
        ObjectWriteResponse resp = null;
        try {
            UploadObjectArgs args =
                    UploadObjectArgs.builder().bucket(bucketName).object(objectKey).filename(filePath)
                            // .contentType("image/png")
                            .build();
            resp = client.uploadObject(args);
        } catch (ErrorResponseException e) {
            e.printStackTrace();
        } catch (InsufficientDataException e) {
            e.printStackTrace();
        } catch (InternalException e) {
            e.printStackTrace();
        } catch (InvalidKeyException e) {
            e.printStackTrace();
        } catch (InvalidResponseException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (ServerException e) {
            e.printStackTrace();
        } catch (XmlParserException e) {
            e.printStackTrace();
        }
        return resp;
    }

    // 上传图片到MinIO并返回保存路径
    public String uploadToMinIO(InputStream is, String objectName, String bucketName) throws Exception {
        client.putObject(
                PutObjectArgs.builder()
                        .bucket(bucketName)
                        .object(objectName)
                        .stream(is, is.available(), -1)
                        .contentType("image/" + objectName.substring(objectName.lastIndexOf(".") + 1))
                        .build()
        );
        return client.getPresignedObjectUrl(
                GetPresignedObjectUrlArgs.builder()
                        .bucket(bucketName)
                        .object(objectName)
                        .method(Method.GET)
                        .build()
        );
    }

    /**
     * 获取全部bucket
     *
     * @return
     */
    public List<Bucket> getAllBuckets() throws Exception {
        return client.listBuckets();
    }

    /**
     * 根据bucketName获取信息
     *
     * @param bucketName bucket名称
     */
    public Optional<Bucket> getBucket(String bucketName) {
        Optional<Bucket> resultOptional = Optional.empty();
        try {
            resultOptional = client.listBuckets().stream().filter(b -> b.name().equals(bucketName)).findFirst();
        } catch (ErrorResponseException e) {
            e.printStackTrace();
        } catch (InsufficientDataException e) {
            e.printStackTrace();
        } catch (InternalException e) {
            e.printStackTrace();
        } catch (InvalidKeyException e) {
            e.printStackTrace();
        } catch (InvalidResponseException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (ServerException e) {
            e.printStackTrace();
        } catch (XmlParserException e) {
            e.printStackTrace();
        }
        return resultOptional;
    }

    /**
     * 根据bucketName删除信息
     *
     * @param bucketName bucket名称
     */
    public void removeBucket(String bucketName) throws Exception {
        client.removeBucket(RemoveBucketArgs.builder().bucket(bucketName).build());
    }

    /**
     * 获取⽂件外链
     *
     * @param bucketName bucket名称
     * @param fileName   ⽂件名称
     * @param expires    过期时间 <=7
     * @return url
     */
    public String getObjectURL(String bucketName, String fileName, Integer expires) throws Exception {
        return client.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder().bucket(bucketName).object(fileName).expiry(expires).build());
    }

    /**
     * 获取⽂件
     *
     * @param bucketName bucket名称
     * @param fileName   ⽂件名称
     * @return ⼆进制流
     */
    public InputStream downloadFile(String bucketName, String fileName) throws Exception {
        return client.getObject(GetObjectArgs.builder().bucket(bucketName).object(fileName).build());
    }

    /**
     * 上传⽂件
     *
     * @param bucketName bucket名称
     * @param objectName ⽂件名称
     * @param stream     ⽂件流
     * @throws Exception https://docs.minio.io/cn/java-client-api-reference.html#putObject
     */
    private void putObject(String bucketName, String objectName, InputStream stream) throws
            Exception {
        client.putObject(PutObjectArgs.builder().bucket(bucketName).object(objectName).stream(stream, stream.available(), -1).contentType(objectName.substring(objectName.lastIndexOf("."))).build());
    }

    /**
     * 上传⽂件
     *
     * @param bucketName  bucket名称
     * @param objectName  ⽂件名称
     * @param stream      ⽂件流
     * @param size        ⼤⼩
     * @param contextType 类型
     * @throws Exception https://docs.minio.io/cn/java-client-api-reference.html#putObject
     */
    public String putObject(String bucketName, String objectName, InputStream stream, long
            size, String contextType) throws Exception {
        client.putObject(PutObjectArgs.builder().bucket(bucketName).object(objectName).stream(stream, size, -1).contentType(contextType).build());
        String url = minioConfig.getUrl() + "/" + bucketName + "/" + objectName;
        log.info("上传文件成功url ：[{}]", url);
        return url;
    }

    /**
     * 获取⽂件信息
     *
     * @param bucketName bucket名称
     * @param fileName   ⽂件名称
     * @throws Exception https://docs.minio.io/cn/java-client-api-reference.html#statObject
     */
    public StatObjectResponse getObjectInfo(String bucketName, String fileName) throws Exception {
        return client.statObject(StatObjectArgs.builder().bucket(bucketName).object(fileName).build());
    }

    /**
     * 删除⽂件
     *
     * @param bucketName bucket名称
     * @param fileName   ⽂件名称
     * @throws Exception https://docs.minio.io/cn/java-client-apireference.html#removeObject
     */
    public void removeObject(String bucketName, String fileName) throws Exception {
        client.removeObject(RemoveObjectArgs.builder().bucket(bucketName).object(fileName).build());
    }

    /**
     * 批量删除⽂件
     *
     * @param bucketName
     * @param objects
     * @throws Exception
     */
    public void removeObjects(String bucketName, List<DeleteObject> objects) throws Exception {
        client.removeObjects(RemoveObjectsArgs.builder().bucket(bucketName).objects(objects).build());
    }


}

